cssnode: Split out the style cache
authorBenjamin Otte <otte@redhat.com>
Fri, 15 Jan 2016 22:27:51 +0000 (23:27 +0100)
committerBenjamin Otte <otte@redhat.com>
Sat, 16 Jan 2016 22:58:37 +0000 (23:58 +0100)
For now, the split out style cache doesn't cache anything. This is
mostly to make sure that bisections of wrong caching behavior will
bisect down to the commit that actually adds caching.

gtk/Makefile.am
gtk/gtkcssnode.c
gtk/gtkcssnodeprivate.h
gtk/gtkcssnodestylecache.c [new file with mode: 0644]
gtk/gtkcssnodestylecacheprivate.h [new file with mode: 0644]

index 120e245e689f5038c1bfc8277f72643dd9ff1c29..516f1bbf32a444f64c0920ca2205e415d52f6b6d 100644 (file)
@@ -416,6 +416,7 @@ gtk_private_h_sources =             \
        gtkcssmatcherprivate.h  \
        gtkcssnodeprivate.h             \
        gtkcssnodedeclarationprivate.h  \
+       gtkcssnodestylecacheprivate.h   \
        gtkcssnumbervalueprivate.h      \
        gtkcsspalettevalueprivate.h     \
        gtkcssparserprivate.h   \
@@ -676,6 +677,7 @@ gtk_base_c_sources =                \
        gtkcssmatcher.c         \
        gtkcssnode.c            \
        gtkcssnodedeclaration.c \
+       gtkcssnodestylecache.c  \
        gtkcssnumbervalue.c     \
        gtkcsspalettevalue.c    \
        gtkcssparser.c          \
index a5dda31a5c480d99a8d5d5f2a2b0bade8afe8240..1106bdbe7add6dd25e64f6f38f73ac371cfe5baf 100644 (file)
 #include "gtkcssnodeprivate.h"
 
 #include "gtkcssanimatedstyleprivate.h"
+#include "gtkcsssectionprivate.h"
+#include "gtkcssstylepropertyprivate.h"
 #include "gtkdebug.h"
 #include "gtkintl.h"
 #include "gtkmarshalers.h"
 #include "gtksettingsprivate.h"
 #include "gtktypebuiltins.h"
-#include "gtkcssstylepropertyprivate.h"
-#include "gtkcsssectionprivate.h"
 
 /*
  * CSS nodes are the backbone of the GtkStyleContext implementation and
@@ -116,8 +116,6 @@ struct _GtkCssNodeStyleChange {
 static guint cssnode_signals[LAST_SIGNAL] = { 0 };
 static GParamSpec *cssnode_properties[NUM_PROPERTIES];
 
-static GQuark quark_global_cache;
-
 static GtkStyleProviderPrivate *
 gtk_css_node_get_style_provider_or_null (GtkCssNode *cssnode)
 {
@@ -285,10 +283,6 @@ gtk_css_node_is_last_child (GtkCssNode *node)
   return TRUE;
 }
 
-#define UNPACK_DECLARATION(packed) ((GtkCssNodeDeclaration *) (GPOINTER_TO_SIZE (packed) & ~0x3))
-#define UNPACK_FLAGS(packed) (GPOINTER_TO_SIZE (packed) & 0x3)
-#define PACK(decl, first_child, last_child) GSIZE_TO_POINTER (GPOINTER_TO_SIZE (decl) | ((first_child) ? 0x2 : 0) | ((last_child) ? 0x1 : 0))
-
 static gboolean
 may_use_global_parent_cache (GtkCssNode *node)
 {
@@ -308,109 +302,52 @@ may_use_global_parent_cache (GtkCssNode *node)
 
 static GtkCssStyle *
 lookup_in_global_parent_cache (GtkCssNode                  *node,
-                               GtkCssStyle                 *parent,
                                const GtkCssNodeDeclaration *decl)
 {
-  GHashTable *cache;
-  GtkCssStyle *style;
+  GtkCssNode *parent;
+
+  parent = node->parent;
 
   if (parent == NULL ||
       !may_use_global_parent_cache (node))
     return NULL;
 
-  cache = g_object_get_qdata (G_OBJECT (parent), quark_global_cache);
-  if (cache == NULL)
+  if (parent->cache == NULL)
     return NULL;
 
-  style = g_hash_table_lookup (cache,
-                               PACK (decl,
-                                     gtk_css_node_is_first_child (node),
-                                     gtk_css_node_is_last_child (node)));
-
-  return style;
-}
-
-static gboolean
-may_be_stored_in_parent_cache (GtkCssStyle *style)
-{
-  GtkCssChange change;
-
-  change = gtk_css_static_style_get_change (GTK_CSS_STATIC_STYLE (style));
-
-  /* The cache is shared between all children of the parent, so if a
-   * style depends on a sibling it is not independant of the child.
-   */
-  if (change & GTK_CSS_CHANGE_ANY_SIBLING)
-    return FALSE;
-
-  /* Again, the cache is shared between all children of the parent.
-   * If the position is relevant, no child has the same style.
-   */
-  if (change & (GTK_CSS_CHANGE_NTH_CHILD | GTK_CSS_CHANGE_NTH_LAST_CHILD))
-    return FALSE;
-
-  return TRUE;
-}
-
-static guint
-gtk_global_parent_cache_hash (gconstpointer item)
-{
-  return gtk_css_node_declaration_hash (UNPACK_DECLARATION (item)) << 2
-    | UNPACK_FLAGS (item);
-}
-
-static gboolean
-gtk_global_parent_cache_equal (gconstpointer item1,
-                               gconstpointer item2)
-{
-  if (UNPACK_FLAGS (item1) != UNPACK_FLAGS (item2))
-    return FALSE;
-
-  return gtk_css_node_declaration_equal (UNPACK_DECLARATION (item1),
-                                         UNPACK_DECLARATION (item2));
-}
+  node->cache = gtk_css_node_style_cache_lookup (parent->cache,
+                                                 (GtkCssNodeDeclaration *) decl,
+                                                 gtk_css_node_is_first_child (node),
+                                                 gtk_css_node_is_last_child (node));
+  if (node->cache == NULL)
+    return NULL;
 
-static void
-gtk_global_parent_cache_free (gpointer item)
-{
-  gtk_css_node_declaration_unref (UNPACK_DECLARATION (item));
+  return gtk_css_node_style_cache_get_style (node->cache);
 }
 
 static void
 store_in_global_parent_cache (GtkCssNode                  *node,
-                              GtkCssStyle                 *parent,
                               const GtkCssNodeDeclaration *decl,
                               GtkCssStyle                 *style)
 {
-  GHashTable *cache;
+  GtkCssNode *parent;
 
   g_assert (GTK_IS_CSS_STATIC_STYLE (style));
 
+  parent = node->parent;
+
   if (parent == NULL ||
       !may_use_global_parent_cache (node))
     return;
 
-  if (!may_be_stored_in_parent_cache (style))
-    return;
-
-  cache = g_object_get_qdata (G_OBJECT (parent), quark_global_cache);
-  if (cache == NULL)
-    {
-      cache = g_hash_table_new_full (gtk_global_parent_cache_hash,
-                                     gtk_global_parent_cache_equal,
-                                     gtk_global_parent_cache_free,
-                                     g_object_unref);
-      g_object_set_qdata_full (G_OBJECT (parent),
-                               quark_global_cache,
-                               cache,
-                               (GDestroyNotify) g_hash_table_destroy);
-    }
+  if (parent->cache == NULL)
+    parent->cache = gtk_css_node_style_cache_new (parent->style);
 
-  g_hash_table_insert (cache,
-                       PACK (gtk_css_node_declaration_ref ((GtkCssNodeDeclaration *) decl),
-                             gtk_css_node_is_first_child (node),
-                             gtk_css_node_is_last_child (node)),
-                       g_object_ref (style));
+  node->cache = gtk_css_node_style_cache_insert (parent->cache,
+                                                 (GtkCssNodeDeclaration *) decl,
+                                                 gtk_css_node_is_first_child (node),
+                                                 gtk_css_node_is_last_child (node),
+                                                 style);
 }
 
 static GtkCssStyle *
@@ -424,7 +361,7 @@ gtk_css_node_create_style (GtkCssNode *cssnode)
   decl = gtk_css_node_get_declaration (cssnode);
   parent = cssnode->parent ? cssnode->parent->style : NULL;
 
-  style = lookup_in_global_parent_cache (cssnode, parent, decl);
+  style = lookup_in_global_parent_cache (cssnode, decl);
   if (style)
     return g_object_ref (style);
 
@@ -437,7 +374,7 @@ gtk_css_node_create_style (GtkCssNode *cssnode)
                                               NULL,
                                               parent);
 
-  store_in_global_parent_cache (cssnode, parent, decl, style);
+  store_in_global_parent_cache (cssnode, decl, style);
 
   return style;
 }
@@ -625,8 +562,6 @@ gtk_css_node_class_init (GtkCssNodeClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
-  quark_global_cache = g_quark_from_static_string ("gtk-global-cache");
-
   object_class->get_property = gtk_css_node_get_property;
   object_class->set_property = gtk_css_node_set_property;
   object_class->dispose = gtk_css_node_dispose;
@@ -1059,6 +994,8 @@ gtk_css_node_ensure_style (GtkCssNode *cssnode,
       if (cssnode->previous_sibling)
         gtk_css_node_ensure_style (cssnode->previous_sibling, current_time);
 
+      g_clear_pointer (&cssnode->cache, gtk_css_node_style_cache_unref);
+
       new_style = GTK_CSS_NODE_GET_CLASS (cssnode)->update_style (cssnode,
                                                                   cssnode->pending_changes,
                                                                   current_time,
@@ -1066,12 +1003,6 @@ gtk_css_node_ensure_style (GtkCssNode *cssnode,
 
       style_changed = gtk_css_node_set_style (cssnode, new_style);
       g_object_unref (new_style);
-
-      if (!style_changed && (cssnode->pending_changes & GTK_CSS_CHANGE_SOURCE))
-        {
-          /* clear the global cache if we reuse the same style after the CSS changed */
-          g_object_set_qdata (G_OBJECT (cssnode->style), quark_global_cache, NULL);
-        }
     }
   else
     {
index 065b8e72a0ba6a706b7916514c4ff5bfca49908a..51d6ceaca39597a3576045261daa9a1c6060f32a 100644 (file)
@@ -19,6 +19,7 @@
 #define __GTK_CSS_NODE_PRIVATE_H__
 
 #include "gtkcssnodedeclarationprivate.h"
+#include "gtkcssnodestylecacheprivate.h"
 #include "gtkcssstylechangeprivate.h"
 #include "gtkbitmaskprivate.h"
 #include "gtkcsstypesprivate.h"
@@ -46,6 +47,7 @@ struct _GtkCssNode
 
   GtkCssNodeDeclaration *decl;
   GtkCssStyle           *style;
+  GtkCssNodeStyleCache  *cache;                 /* cache for children to look up styles */
 
   GtkCssChange           pending_changes;       /* changes that accumulated since the style was last computed */
 
diff --git a/gtk/gtkcssnodestylecache.c b/gtk/gtkcssnodestylecache.c
new file mode 100644 (file)
index 0000000..5c4e61d
--- /dev/null
@@ -0,0 +1,76 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 2015 Benjamin Otte <otte@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include "gtkcssnodestylecacheprivate.h"
+
+struct _GtkCssNodeStyleCache {
+  guint        ref_count;
+  GtkCssStyle *style;
+  GHashTable  *children;
+};
+
+GtkCssNodeStyleCache *
+gtk_css_node_style_cache_new (GtkCssStyle *style)
+{
+  GtkCssNodeStyleCache *result;
+
+  result = g_slice_new0 (GtkCssNodeStyleCache);
+
+  result->ref_count = 1;
+  result->style = g_object_ref (style);
+
+  return result;
+}
+
+void
+gtk_css_node_style_cache_unref (GtkCssNodeStyleCache *cache)
+{
+  cache->ref_count--; 
+
+  if (cache->ref_count > 0)
+    return;
+
+  g_object_unref (cache->style);
+}
+
+GtkCssStyle *
+gtk_css_node_style_cache_get_style (GtkCssNodeStyleCache *cache)
+{
+  return cache->style;
+}
+
+GtkCssNodeStyleCache *
+gtk_css_node_style_cache_insert (GtkCssNodeStyleCache   *parent,
+                                 GtkCssNodeDeclaration  *decl,
+                                 gboolean                is_first,
+                                 gboolean                is_last,
+                                 GtkCssStyle            *style)
+{
+  return gtk_css_node_style_cache_new (style);
+}
+
+GtkCssNodeStyleCache *
+gtk_css_node_style_cache_lookup (GtkCssNodeStyleCache   *parent,
+                                 GtkCssNodeDeclaration  *decl,
+                                 gboolean                is_first,
+                                 gboolean                is_last)
+{
+  return NULL;
+}
+
diff --git a/gtk/gtkcssnodestylecacheprivate.h b/gtk/gtkcssnodestylecacheprivate.h
new file mode 100644 (file)
index 0000000..c406fbf
--- /dev/null
@@ -0,0 +1,44 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 2016 Benjamin Otte <otte@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GTK_CSS_NODE_STYLE_CACHE_PRIVATE_H__
+#define __GTK_CSS_NODE_STYLE_CACHE_PRIVATE_H__
+
+#include "gtkcssstyleprivate.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GtkCssNodeStyleCache GtkCssNodeStyleCache;
+
+GtkCssNodeStyleCache *  gtk_css_node_style_cache_new            (GtkCssStyle            *style);
+void                    gtk_css_node_style_cache_unref          (GtkCssNodeStyleCache   *cache);
+
+GtkCssStyle *           gtk_css_node_style_cache_get_style      (GtkCssNodeStyleCache   *cache);
+
+GtkCssNodeStyleCache *  gtk_css_node_style_cache_insert         (GtkCssNodeStyleCache   *parent,
+                                                                 GtkCssNodeDeclaration  *decl,
+                                                                 gboolean                is_first,
+                                                                 gboolean                is_last,
+                                                                 GtkCssStyle            *style);
+GtkCssNodeStyleCache *  gtk_css_node_style_cache_lookup         (GtkCssNodeStyleCache   *parent,
+                                                                 GtkCssNodeDeclaration  *decl,
+                                                                 gboolean                is_first,
+                                                                 gboolean                is_last);
+
+G_END_DECLS
+
+#endif /* __GTK_CSS_NODE_STYLE_CACHE_PRIVATE_H__ */